// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2024, Phytium Technology Co., Ltd.
 * This file describes the Phytium SCMI API
 */

#include <common.h>
#include <command.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <malloc.h>
#include <scmi_protocols.h>
#include "../cpu.h"
#include "board.h"

/* send command */
void scmi_send_sync_command(mailbox_mem_e_t *mbx_mem)
{
	/* mark the channel as busy */
	SCMI_MARK_CHANNEL_BUSY(mbx_mem->status);
	dmb();
	/* write the message header to trigger the command to send */
	writel(mbx_mem->msg_header, AP_UBOOT_SET);
	dmb();
	/* wait for channel to be free */
	while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status));
	dmb();
}

/*phytium scmi api.scmi communication between the AP and the SCP*/
int phytium_scmi(uint32_t count, ...)
{
	uint32_t protocol_id, message_id;
	uint32_t *argv;
	va_list args;
	int length, i;
	mailbox_mem_e_t *mbx_mem, *mbx_mem_back;

	argv = (uint32_t *)malloc(sizeof(uint32_t) * count);
	memset(argv, 0, sizeof(int) * count);

	/* Shielding the interrupt of MBX channel 0 */
	writel(0x1, AP_UBOOT_CONFIG);
	mbx_mem = (mailbox_mem_e_t *)AP_TO_SCP_SHARED_MEM_BASE;

	/* Get variable parameters, used to construct msg for scmi transport */
	va_start(args, count);
	protocol_id = va_arg(args, uint32_t);
	message_id = va_arg(args, uint32_t);
	for (i = 0; i < (count - 1); i++)
		mbx_mem->payload[i] = va_arg(args, uint32_t);
	va_end(args);

	printf("Phytium scmi:\n");
	printf("AP -> SCP:\n");
	printf("protocol_id:0x%x\nmessage_id:0x%x\n", protocol_id, message_id);
	for (i = 2; i <= (count - 2); i++)
		printf("payload[%d]:0x%x\n", i, argv[i]);

	/* fill the mailbox and initiate virtual channel communication */
	mbx_mem->len = (sizeof(mbx_mem->msg_header) + ((count - 2) * 4));
	mbx_mem->msg_header = SCMI_MSG_CREATE_E(protocol_id, message_id, 0);
	mbx_mem->flags = 0x0;
	mbx_mem->status = 0x0;
	//write AP-UBOOT_SET reg, 0 invalid, 1 status reg is set
	writel(mbx_mem->msg_header, AP_UBOOT_SET);

	scmi_send_sync_command(mbx_mem);
	mbx_mem_back = mbx_mem;

	/* Determine whether the AP is successfully sent, and make a judgment on the SCP response */
	if (mbx_mem_back->payload[0] != SCMI_SUCCESS) {
		printf("SCMI ERROR:protocol_id:0x%x, message_id:0x%x, error is:0x%x\n", protocol_id, message_id, (mbx_mem_back->payload[0]));
		return -1;
	} else {
		printf("SCP -> AP:\n");
		length = (mbx_mem_back->len) - sizeof(mbx_mem_back->msg_header);
		for (i = 0; length > 0; i++) {
			printf("payload[%d]:0x%x\n", i, mbx_mem_back->payload[i]);
			length -= 4;
		}
	}

	return 0;
}

/* processing the input parameters of the command line */
static int do_scmi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	uint32_t parm[SCMI_MAX_PARM_CPUNT] = { 0 };
	uint32_t count = simple_strtoul(argv[1], NULL, 16);
	int i;

	if (argc < 4)
		return CMD_RET_USAGE;

	for (i = 0; i < count; i++)
		parm[i] = simple_strtoul(argv[i + 2], NULL, 16);

	/* command handle */
	phytium_scmi(count, parm[0], parm[1], parm[2], parm[3], parm[4], parm[5], parm[6], parm[7], parm[8], parm[9]);

	return 0;
}

/* Command registration */
U_BOOT_CMD(
	scmi, 10, 0, do_scmi,
	"scmi command",
	"[count-max:10] [protocol_id] [message_id] [payload...]"
);
